<?php

namespace auth;

use app\admin\model\base\AdminMenu;
use app\admin\model\base\AdminRole;
use app\admin\model\base\AdminRoleAccess;

/**
 * 权限认证类
 */
class Auth
{
    /**
     * 认证方式，1为实时认证；2为登录认证。
     * @var int
     */
    protected int $_auth_type = 1;

    /**
     * 检查权限
     * @param $rule string  需要验证的规则列表,支持逗号分隔的权限规则或索引数组
     * @param string $mode 执行check的模式
     * @param $relation string    如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
     * @return boolean           通过验证返回true;失败返回false
     */
    public function check(string $rule, string $mode = 'url', string $relation = 'or'): bool
    {
        $rules = [
            '/admin/base/adminLogin',
            '/admin/base/adminLogout',
            '/admin/base/adminInfo',
            '/admin/base/authRouters',
        ];
        //超级管理员拥有全部权限
        $admin_id = WS_ADMIN_ID;
        if ($admin_id === 1 or in_array($rule, $rules)) {
            return true;
        } elseif (!$admin_id) {
            return false;
        }
        //获取用户需要验证的所有有效规则列表
        $authList = $this->getAuthList($admin_id);
        if (is_string($rule)) {
            $rule = strtolower($rule);
            if (str_contains($rule, ',')) {
                $rule = explode(',', $rule);
            } else {
                $rule = array($rule);
            }
        }
        $list = array(); //保存验证通过的规则名
        if ($mode == 'url') {
            $REQUEST = unserialize(strtolower(serialize($_REQUEST)));
        }
        foreach ($authList as $auth) {
            $query = preg_replace('/^.+\?/U', '', $auth);
            if ($mode == 'url' && $query != $auth) {
                parse_str($query, $param); //解析规则中的param
                $intersect = array_intersect_assoc($REQUEST, $param);
                $auth = preg_replace('/\?.*$/U', '', $auth);
                if (in_array($auth, $rule) && $intersect == $param) {  //如果节点相符且url参数满足
                    $list[] = $auth;
                }
            } else if (in_array($auth, $rule)) {
                $list[] = $auth;
            }
        }
        if ($relation == 'or' and !empty($list)) {
            return true;
        }
        $diff = array_diff($rule, $list);
        if ($relation == 'and' and empty($diff)) {
            return true;
        }
        return false;
    }

    /**
     * 获得权限列表
     * @param int $admin_id
     * @return array|null
     */
    public function getAuthList(int $admin_id): array|null
    {
        static $_authList = array(); //保存用户验证通过的权限列表
        if (isset($_authList[$admin_id])) {
            return $_authList[$admin_id];
        }
        if ($this->_auth_type == 2 && isset($_SESSION['_auth_list_' . $admin_id])) {
            return $_SESSION['_auth_list_' . $admin_id];
        }
        //读取用户所属用户组
        $groups = $this->getRoles($admin_id);
        $ids = array();//保存用户所属用户组设置的所有权限规则id
        foreach ($groups as $g) {
            $ids = array_merge($ids, explode(',', trim($g['menu_ids'], ',')));
        }
        $ids = array_unique($ids);
        if (empty($ids)) {
            $_authList[$admin_id] = array();
            return array();
        }
        $ids = array_map('intval', $ids);
        $map[] = ['id', 'in', $ids];
        $map[] = ['status', '=', 1];
        //读取用户组所有权限规则
        $rules = AdminMenu::where($map)->field('rule')->select();
        //循环规则，判断结果。
        $authList = array();
        foreach ($rules as $rule) {
            //只要存在就记录
            $authList[] = strtolower($rule['rule']);
        }
        $_authList[$admin_id] = $authList;
        if ($this->_auth_type == 2) {
            //规则列表结果保存到session
            $_SESSION['_auth_list_' . $admin_id] = $authList;
        }
        return array_unique($authList);
    }

    /**
     * 用于管理员信息权限列表
     * @param int $admin_id
     * @return array|null
     */
    public function getAuthList2(int $admin_id): array|null
    {
        //读取用户所属用户组
        $groups = $this->getRoles($admin_id);
        $ids = array();//保存用户所属用户组设置的所有权限规则id
        foreach ($groups as $g) {
            $ids = array_merge($ids, explode(',', trim($g['menu_ids'], ',')));
        }
        $ids = array_unique($ids);
        if (empty($ids)) {
            return array();
        }
        $ids = array_map('intval', $ids);
        $map[] = ['id', 'in', $ids];
        $map[] = ['status', '=', 1];
        //读取用户组所有权限规则
        $rules = AdminMenu::where($map)->field('rule')->select();
        //循环规则，判断结果。
        $authList = array();
        foreach ($rules as $rule) {
            //只要存在就记录
            $authList[] = $rule['rule'];
        }
        return array_unique($authList);
    }

    /**
     * 根据用户id获取角色组,返回值为数组
     * @param  $admin_id int     用户id
     * @return array       用户所属的用户组
     */
    public function getRoles(int $admin_id): array
    {
        static $groups = array();
        if (isset($groups[$admin_id])) {
            return $groups[$admin_id];
        }
        $user_groups = AdminRoleAccess::alias('a')
            ->where("a.admin_id='$admin_id' and g.status='1'")
            ->join((new AdminRole())->getTable() . ' g', 'a.role_id=g.id')
            ->field('a.admin_id,a.role_id,g.role_name,g.menu_ids')
            ->cache(true, 30)
            ->select();
        $groups[$admin_id] = $user_groups ? $user_groups->toArray() : [];
        return $groups[$admin_id];
    }

}
